import { Router } from 'express';
import { body } from 'express-validator';
import validateFormData from '../helpers/validate_form.js';
import DB from '../models/db.js';
import path from 'path';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import { Worker } from 'worker_threads';
import EthersUtils from '../helpers/ethers_utils.js';
import config from '../config.js';
import fs from 'fs';


const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);


const router = Router();




/**
 * Route to list studentgradesummary records
 * @GET /studentgradesummary/index/{fieldname}/{fieldvalue}
 */
router.get(['/', '/index/:fieldname?/:fieldvalue?'], async (req, res) => {
	try {
		const query = {};
		let queryFilters = [];
		let where = {};
		let replacements = {};
		let fieldName = req.params.fieldname;
		let fieldValue = req.params.fieldvalue;

		if (fieldName) {
			queryFilters.push(DB.filterBy(fieldName, fieldValue));
		}
		let search = req.query.search;
		if (search) {
			let searchFields = DB.Studentgradesummary.searchFields();
			where[DB.op.or] = searchFields;
			replacements.search = `%${search}%`;
		}

		let allowedRoles = ["admin", "eduadmin"];
		let userRole = req.userRoleName;
		if(!allowedRoles.includes(userRole)){
			if(userRole === "student")where['student_id'] = req.user.user_id; //filter only current records
			
		}

		if (queryFilters.length) {
			where[DB.op.and] = queryFilters;
		}
		query.raw = true;
		query.where = where;
		query.replacements = replacements;
		query.order = DB.getOrderBy(req, 'summary_id', 'desc');
		query.attributes = DB.Studentgradesummary.listFields();
		let page = parseInt(req.query.page) || 1;
		let limit = parseInt(req.query.limit) || 10;
		let result = await DB.Studentgradesummary.paginate(query, page, limit);
		return res.ok(result);
	}
	catch (err) {
		return res.serverError(err);
	}
});


/**
 * Route to view Studentgradesummary record
 * @GET /studentgradesummary/view/{recid}
 */
router.get('/view/:recid', async (req, res) => {
	try {
		const recid = req.params.recid || null;
		const query = {}
		const where = {}
		where['summary_id'] = recid;
		query.raw = true;
		query.where = where;
		query.attributes = DB.Studentgradesummary.viewFields();
		let record = await DB.Studentgradesummary.findOne(query);
		if (!record) {
			return res.notFound();
		}
		return res.ok(record);
	}
	catch (err) {
		return res.serverError(err);
	}
});


/**
 * Route to insert Studentgradesummary record
 * @POST /studentgradesummary/add
 */
router.post('/add/',
	[
		body('student_id').not().isEmpty(),
		body('semester_name').not().isEmpty(),
		body('semester_start').not().isEmpty(),
		body('semester_end').not().isEmpty(),
		body('grade_data').not().isEmpty(),
		body('data_hash').not().isEmpty(),
		body('transaction_hash').optional({ nullable: true, checkFalsy: true }),
		body('onchain_status').optional({ nullable: true, checkFalsy: true }),
		body('onchain_time').optional({ nullable: true, checkFalsy: true }),
	], validateFormData
	, async function (req, res) {
		try {
			let modeldata = req.getValidFormData();

			//save Studentgradesummary record
			let record = await DB.Studentgradesummary.create(modeldata);
			//await record.reload(); //reload the record from database
			const recid = record['summary_id'];

			return res.ok(record);
		} catch (err) {
			return res.serverError(err);
		}
	});


/**
 * Route to get  Studentgradesummary record for edit
 * @GET /studentgradesummary/edit/{recid}
 */
router.get('/edit/:recid', async (req, res) => {
	try {
		const recid = req.params.recid;
		const query = {};
		const where = {};
		where['summary_id'] = recid;
		query.raw = true;
		query.where = where;
		query.attributes = DB.Studentgradesummary.editFields();
		let record = await DB.Studentgradesummary.findOne(query);
		if (!record) {
			return res.notFound();
		}
		return res.ok(record);
	}
	catch (err) {
		return res.serverError(err);
	}
});


/**
 * Route to update  Studentgradesummary record
 * @POST /studentgradesummary/edit/{recid}
 */
router.post('/edit/:recid',
	[
		body('student_id').optional({ nullable: true }).not().isEmpty(),
		body('semester_name').optional({ nullable: true }).not().isEmpty(),
		body('semester_start').optional({ nullable: true }).not().isEmpty(),
		body('semester_end').optional({ nullable: true }).not().isEmpty(),
		body('grade_data').optional({ nullable: true }).not().isEmpty(),
		body('data_hash').optional({ nullable: true }).not().isEmpty(),
		body('transaction_hash').optional({ nullable: true, checkFalsy: true }),
		body('onchain_status').optional({ nullable: true, checkFalsy: true }),
		body('onchain_time').optional({ nullable: true, checkFalsy: true }),
	], validateFormData
	, async (req, res) => {
		try {
			const recid = req.params.recid;
			let modeldata = req.getValidFormData({ includeOptionals: true });
			const query = {};
			const where = {};
			where['summary_id'] = recid;
			query.raw = true;
			query.where = where;
			query.attributes = DB.Studentgradesummary.editFields();
			let record = await DB.Studentgradesummary.findOne(query);
			if (!record) {
				return res.notFound();
			}
			await DB.Studentgradesummary.update(modeldata, { where: where });
			return res.ok(modeldata);
		}
		catch (err) {
			return res.serverError(err);
		}
	});


/**
 * Route to delete Studentgradesummary record by table primary key
 * Multi delete supported by recid separated by comma(,)
 * @GET /studentgradesummary/delete/{recid}
 */
router.get('/delete/:recid', async (req, res) => {
	try {
		const recid = (req.params.recid || '').split(',');
		const query = {};
		const where = {};
		where['summary_id'] = recid;
		query.raw = true;
		query.where = where;
		let records = await DB.Studentgradesummary.findAll(query);
		records.forEach(async (record) => {
			//perform action on each record before delete
		});
		await DB.Studentgradesummary.destroy(query);
		return res.ok(recid);
	}
	catch (err) {
		return res.serverError(err);
	}
});


/**
 * 批量生成所有学生成绩报表PDF并保存记录
 * @POST /studentgradesummary/batch-generate-reports
 */
router.post('/batch-generate-reports',
	[body('semester_name').not().isEmpty()],
	validateFormData,
	async (req, res) => {
		try {
			const { semester_name } = req.getValidFormData();
			const MAX_CONCURRENT_WORKERS = 2; // 限制最大并发工作线程数
			const BATCH_SIZE = 10; // 每批处理的学生数量

			// 查询所有学生信息
			const students = await DB.Users.findAll({
				where: { user_role_id: 2 },
				attributes: ['user_id', 'name', 'personnel_id', 'ethereum_address']
			});

			if (!students.length) {
				return res.badRequest("没有找到学生记录");
			}

			// 立即返回响应
			res.ok({
				message: "报告生成任务已开始处理",
				total_students: students.length,
				status: 'processing',
			});

			// 为所有学生创建初始记录
			const summaryRecords = await Promise.all(students.map(async student => {
				return await DB.Studentgradesummary.create({
					student_id: student.user_id,
					semester_name,
					processing_status: 'processing',
					student_address: student.ethereum_address,
					
				});
			}));

			console.log("学生创建初始记录成功");

			// 将学生分批处理
			for (let i = 0; i < students.length; i += BATCH_SIZE) {
				const batchStudents = students.slice(i, i + BATCH_SIZE);
				const batchSummaryRecords = summaryRecords.slice(i, i + BATCH_SIZE);

				// 使用Promise.all和并发限制处理每一批学生
				await Promise.all(
					batchStudents.map((student, batchIndex) => 
						processStudentWithConcurrencyLimit(
							student,
							batchSummaryRecords[batchIndex],
							semester_name,
							MAX_CONCURRENT_WORKERS
						)
					)
				);

				// 每批处理完后等待一小段时间，让系统资源得到释放
				await new Promise(resolve => setTimeout(resolve, 1000));
			}
		} catch (err) {
			console.error("批量生成成绩报表出错:", err);
		}
	}
);

// 处理单个学生的函数，包含并发限制
async function processStudentWithConcurrencyLimit(student, summaryRecord, semester_name, maxConcurrent) {
	// 使用信号量控制并发
	const semaphore = {
		count: 0,
		queue: [],
		async acquire() {
			if (this.count >= maxConcurrent) {
				await new Promise(resolve => this.queue.push(resolve));
			}
			this.count++;
		},
		release() {
			this.count--;
			if (this.queue.length > 0) {
				const next = this.queue.shift();
				next();
			}
		}
	};

	try {
		await semaphore.acquire();

		const records = await DB.Enrollments.findAll({
			where: { 
				student_id: student.user_id,
				'$grades.semester_name$': semester_name  // 修改为使用grades表的semester_name字段
			},
			include: [
				{
					model: DB.Grades,
					as: 'grades',
					required: true,
					attributes: ['grade_id', 'daily_grade', 'exam_grade', 'homework_grade',
						'final_grade', 'teacher_feedback', 'last_updated',
						'updated_by', 'teacher_signature','semester_name']
				},
				{
					model: DB.Courses,
					as: 'course',
					attributes: ['course_name']
				}
			],
			attributes: ['enrollment_id', 'enrollment_date'],
			raw: true,
			nest: true
		});

		if (!records.length) {
			await DB.Studentgradesummary.update({
				processing_status: 'completed',
				pdf_path: null
			}, {
				where: { summary_id: summaryRecord.summary_id }
			});
			return;
		}

		const formattedRecords = records.map(record => ({
			grade_id: record.grades.grade_id,
			enrollment_id: record.enrollment_id,
			daily_grade: record.grades.daily_grade,
			exam_grade: record.grades.exam_grade,
			homework_grade: record.grades.homework_grade,
			final_grade: record.grades.final_grade,
			teacher_feedback: record.grades.teacher_feedback,
			last_updated: record.grades.last_updated,
			updated_by: record.grades.updated_by,
			teacher_signature: record.grades.teacher_signature,
			semester_name:record.grades.semester_name,
			enrollment_course_name: record.course.course_name,
			enrollment_enrollment_date: record.enrollment_date
		}));

		// 启动工作线程
		const worker = new Worker(path.join(__dirname, '../workers/gradeReportWorker.js'), {
			workerData: {
				student,
				semester_name,
				formattedRecords,
				summary_id: summaryRecord.summary_id
			}
		});

		// 使用Promise包装工作线程的处理
		await new Promise((resolve, reject) => {
			worker.on('message', async (message) => {
				try {
					await DB.Studentgradesummary.update({
						processing_status: 'completed',
						pdf_path: message.pdf_path,
						cid: message.ipfsHash,
						data_hash: message.data_hash
					}, {
						where: { summary_id: message.summary_id }
					});
					resolve();
				} catch (error) {
					reject(error);
				}
			});

			worker.on('error', async (error) => {
				await DB.Studentgradesummary.update({
					processing_status: 'failed',
					error_message: error.message
				}, {
					where: { summary_id: summaryRecord.summary_id }
				});
				reject(error);
			});

			worker.on('exit', (code) => {
				if (code !== 0) {
					reject(new Error(`工作线程异常退出，代码: ${code}`));
				}
			});
		});

	} catch (err) {
		console.error(`处理学生 ${student.user_id} 时出错:`, err);
		await DB.Studentgradesummary.update({
			processing_status: 'failed',
			error_message: err.message
		}, {
			where: { summary_id: summaryRecord.summary_id }
		});
	} finally {
		semaphore.release();
	}
}

router.get('/report-status/:student_id/:semester_name', async (req, res) => {
	try {
		const record = await DB.Studentgradesummary.findOne({
			where: {
				student_id: req.params.student_id,
				semester_name: req.params.semester_name
			}
		});

		if (!record) {
			return res.notFound('记录不存在');
		}

		res.ok({
			status: record.processing_status,
			pdf_url: record.pdf_path,
			cid: record.cid,
			error: record.error_message
		});
	} catch (err) {
		res.serverError(err);
	}
});

/**
 * 批量获取学生成绩汇总记录并生成批次哈希
 * @GET /studentgradesummary/batch-reports
 */
router.get('/batch-reports', async (req, res) => {
    try {
        // 1. 从数据库获取所有学生成绩记录
        const records = await DB.Studentgradesummary.findAll({
            attributes: ['summary_id', 'student_address', 'semester_name', 'cid', 'registrar_sig'],
            raw: true
        });

        if (!records.length) {
            return res.ok([]);
        }

        // 2. 按100条一组分组
        const batchSize = 100;
        const batches = [];

		// 读取逻辑合约ABI
					const logicContractPath = path.resolve(
						__dirname,
						'../helpers/build/contracts/GradeLogicV1.json'
					);
					
					if (!fs.existsSync(logicContractPath)) {
						return res.badRequest('Logic contract ABI not found');
					}
		
					const logicContractData = JSON.parse(fs.readFileSync(logicContractPath, 'utf8'));
					

		const ethersUtils = new EthersUtils(config.eth.privateKey);
		const chainId = await ethersUtils.getChainId();

				// 1. 从数据库获取合约信息
		const contract = await DB.SmartContracts.findOne({
			where: { contract_name: 'GradeLogicV1' },
			raw: true
		});

		if (!contract) {
			return res.badRequest('未找到GradeLogicV1合约记录');
		}

		const contractInstance = ethersUtils.getContract(contract.contract_address, logicContractData.abi)
        
        for (let i = 0; i < records.length; i += batchSize) {
            const batch = records.slice(i, i + batchSize);
            
            // 3. 转换数据结构为ReportInput格式
            const reportsInput = batch.map(record => ({
                student: record.student_address,
                semester: record.semester_name,
                cid: record.cid,
                registrarSig: record.registrar_sig || "0x" // 如果没有签名则使用空值
            }));

			console.log("reportsInput:", reportsInput)

            // 4. 生成批次哈希
            const batchHash = await contractInstance.getBatchHash(reportsInput);
			const getBatchSignHash = await contractInstance.getBatchSignHash(req.user.ethereum_address,reportsInput);

			
            
            // 5. 更新数据库中的批次哈希
            const summaryIds = batch.map(record => record.summary_id);
            await DB.Studentgradesummary.update({
                batch_hash: batchHash,
				onchain_status: 'pending'
            }, {
                where: {
                    summary_id: {
                        [DB.op.in]: summaryIds
                    }
                }
            });

            batches.push({
                reports: reportsInput,
                batchHash: batchHash,
				messageToSign: getBatchSignHash
            });
        }

        return res.ok(batches);
    } catch (err) {
        console.error('获取批量报告出错:', err);
        return res.serverError(err);
    }
});

/**
 * 获取所有学生成绩汇总记录的哈希值
 * @GET /studentgradesummary/report-hashes
 */
router.get('/report-hashes', async (req, res) => {
	try {
		// 1. 从数据库获取合约信息
		const contract = await DB.SmartContracts.findOne({
			where: { contract_name: 'GradeLogicV1' },
			raw: true
		});

		if (!contract) {
			return res.badRequest('未找到GradeLogicV1合约记录');
		}

		// 2. 获取学生成绩记录
		const records = await DB.Studentgradesummary.findAll({
			attributes: ['summary_id', 'student_address', 'semester_name', 'data_hash', 'cid'],
			raw: true
		});

		const ethersUtils = new EthersUtils(config.eth.privateKey);
		const chainId = await ethersUtils.getChainId();

		

		// 3. 构建哈希映射对象
		const hashMap = records.reduce((acc, record) => {

			const signHash = ethersUtils.generateCustomHash(
				['uint256', 'address', 'string', 'address', 'address', 'string', 'string'],
				[
					chainId,
					contract.contract_address,
					"REGISTRAR_SIG",
					req.user.ethereum_address,
					record.student_address,
					record.semester_name,
					record.cid
				]
			);
			

			acc[record.summary_id] = signHash;
			return acc;
		}, {});

		return res.ok(hashMap);
	} catch (err) {
		return res.serverError(err);
	}
});

/**
 * 保存教务签名（暂不上链）
 * @POST /studentgradesummary/save-registrar-signature
 */
router.post('/save-registrar-signature',
	[
		body('summary_id').not().isEmpty(),
		body('signature').not().isEmpty()
	],
	validateFormData,
	async (req, res) => {
		try {
			const { summary_id, signature } = req.getValidFormData();

			// 1. 验证记录存在
			const record = await DB.Studentgradesummary.findOne({
				where: { summary_id }
			});

			if (!record) {
				return res.notFound('记录不存在');
			}

			// 2. 更新数据库中的签名字段
			await DB.Studentgradesummary.update({
				registrar_sig: signature,
				registrar_address:req.user.ethereum_address
			}, {
				where: { summary_id }
			});

			return res.ok({
				message: '教务签名已保存',
				summary_id
			});

		} catch (err) {
			console.error('保存签名出错:', err);
			return res.serverError(err);
		}
	}
);

/**
 * 更新批次上链状态
 * @POST /studentgradesummary/update-batch-onchain-status
 */
router.post('/update-batch-onchain-status',
    [
        body('batchHash').not().isEmpty(),
        body('transactionHash').not().isEmpty()
    ],
    validateFormData,
    async (req, res) => {
        try {
            const { batchHash, transactionHash } = req.getValidFormData();

            // 1. 更新该批次所有记录的上链状态
            await DB.Studentgradesummary.update({
                onchain_status: 'confirmed',
                transaction_hash: transactionHash,
                onchain_time: new Date()
            }, {
                where: {
                    batch_hash: batchHash
                }
            });

            return res.ok({
                message: '批次上链状态更新成功',
                batchHash,
                transactionHash
            });

        } catch (err) {
            console.error('更新批次上链状态出错:', err);
            return res.serverError(err);
        }
    }
);



/**
 * 获取学生确认信息的哈希值
 * @GET /studentgradesummary/student-confirm-hash/:summary_id
 */
router.get('/student-confirm-hash/:summary_id', async (req, res) => {
    try {
        // 1. 从数据库获取合约信息
        const contract = await DB.SmartContracts.findOne({
            where: { contract_name: 'GradeLogicV1' },
            raw: true
        });

        if (!contract) {
            return res.badRequest('未找到GradeLogicV1合约记录');
        }

        // 2. 获取指定summary_id的学生成绩记录
        const record = await DB.Studentgradesummary.findOne({
            where: { summary_id: req.params.summary_id },
            attributes: ['summary_id', 'student_address', 'semester_name', 'cid'],
            raw: true
        });

        if (!record) {
            return res.notFound('未找到指定记录');
        }

        const ethersUtils = new EthersUtils(config.eth.privateKey);
        const chainId = await ethersUtils.getChainId();

        // 3. 生成哈希
        const signHash = ethersUtils.generateCustomHash(
            ['uint256', 'address', 'string', 'address', 'string', 'string'],
            [
                chainId,
                contract.contract_address,
                "STUDENT_SIG",
                record.student_address,
                record.cid,
                record.semester_name
            ]
        );

       

        return res.ok({
            summary_id: record.summary_id,
            hash: signHash
        });
    } catch (err) {
        return res.serverError(err);
    }
});


/**
 * 更新学生确认状态
 * @POST /studentgradesummary/update-confirm-status/:summary_id
 */
router.post('/update-confirm-status/:summary_id', 
    [
        body('confirm_status').not().isEmpty().isIn(['not_confirm', 'confirming', 'confirmed']),
        body('student_sig').optional()
    ],
    validateFormData,
    async (req, res) => {
        try {
            const { summary_id } = req.params;
            const { confirm_status, student_sig } = req.getValidFormData();

            // 1. 验证记录存在
            const record = await DB.Studentgradesummary.findOne({
                where: { summary_id }
            });

            if (!record) {
                return res.notFound('未找到指定记录');
            }

            // 2. 更新确认状态
            const updateData = {
                confirm_status
            };

            if (student_sig) {
                updateData.student_sig = student_sig;
            }

            await DB.Studentgradesummary.update(updateData, {
                where: { summary_id }
            });

            return res.ok({
                message: '确认状态更新成功',
                summary_id,
                confirm_status
            });

        } catch (err) {
            console.error('更新确认状态出错:', err);
            return res.serverError(err);
        }
    }
);

/**
 * 验证教务签名
 * @POST /studentgradesummary/verify-registrar-signature
 */
router.post('/verify-registrar-signature',
    [
        body('summary_id').not().isEmpty(),
        body('signature').not().isEmpty()
    ],
    validateFormData,
    async (req, res) => {
        try {
            const { summary_id, signature } = req.getValidFormData();

            // 1. 获取合约信息
            const contract = await DB.SmartContracts.findOne({
                where: { contract_name: 'GradeLogicV1' },
                raw: true
            });

            if (!contract) {
                return res.badRequest('未找到GradeLogicV1合约记录');
            }

            // 2. 获取学生成绩记录
            const record = await DB.Studentgradesummary.findOne({
                where: { summary_id },
                attributes: ['summary_id', 'student_address', 'registrar_address','semester_name', 'cid'],
                raw: true
            });

            if (!record) {
                return res.notFound('未找到指定记录');
            }

            // 3. 生成哈希
            const ethersUtils = new EthersUtils(config.eth.privateKey);
            const chainId = await ethersUtils.getChainId();

			console.log(record.registrar_address);

            const signHash = ethersUtils.generateCustomHash(
                ['uint256', 'address', 'string', 'address', 'address', 'string', 'string'],
                [
                    chainId,
                    contract.contract_address,
                    "REGISTRAR_SIG",
                    record.registrar_address,
                    record.student_address,
                    record.semester_name,
                    record.cid
                ]
            );
			

			const messageBytes = ethersUtils.getEthers().getBytes(signHash);
			const registrarAddress = ethersUtils.getEthers().verifyMessage(messageBytes, signature);

            if (!registrarAddress) {
                return res.badRequest({
                    success: false,
                    message: '签名验证失败'
                });
            }

			console.log(registrarAddress);

            // 5. 在数据库中查找匹配的教务
            const registrar = await DB.Users.findOne({
                where: {
                    ethereum_address: registrarAddress,
                    user_role_id: 3 // 教务角色ID
                },
                attributes: ['personnel_id', 'name']
            });

			console.log(registrar);

            if (!registrar) {
                return res.ok({
                    success: false,
                    message: '未找到匹配的教务信息'
                });
            }

            return res.ok({
                success: true,
                summary_id,
                is_valid: true,
                registrarName: registrar.name,
                registrarId: registrar.personnel_id,
                message: '签名验证通过'
            });

        } catch (err) {
            console.error('验证教务签名出错:', err);
            return res.serverError(err);
        }
    }
);

export default router;
